#include "Model.h"
#include "../../tools/xml/ticpp.h"
#include "../../tools/Log.h"

void Model::load(const char *filename) {
	using namespace ticpp;
	try {
		std::string val;
		Document doc( filename );
		doc.LoadFile();
		
		Node* node = doc.FirstChild(), *lists = NULL;
		while((lists = node->IterateChildren( lists)) != NULL) {
			lists->GetValue(&val);
			if(val == "ModelList") {
				Node *child = NULL;
				while( (child = lists->IterateChildren( child )) != NULL) {
					child->GetValue(&val);
					if(val != "model")
						throw Exception("ModelList element was not a model");
					Element* elem = child->ToElement();
					elem->GetAttribute("name", &val, true);
					
					GeometryModel &g = models[val];
					elem->GetAttribute("file", &val, true);
					g.load(val.c_str());
					
					elem->GetAttribute("x", &g.localPosition.x, false);
					elem->GetAttribute("y", &g.localPosition.y, false);
					elem->GetAttribute("z", &g.localPosition.z, false);
					elem->GetAttribute("rotX", &g.localRotation.x, false);
					elem->GetAttribute("rotY", &g.localRotation.y, false);
					elem->GetAttribute("rotZ", &g.localRotation.z, false);
					elem->GetAttribute("scaleX", &g.scale.x, false);
					elem->GetAttribute("scaleY", &g.scale.y, false);
					elem->GetAttribute("scaleZ", &g.scale.z, false);
				}
			} else if(val == "AttributeList") {
				Node *child = NULL;
				while( (child = lists->IterateChildren( child )) != NULL) {
					child->GetValue(&val);
					if(val != "Attribute")
						throw Exception("AttributeList had an element not of type Attribute, but "+ val);
				//	Element* elem = child->ToElement();
					
					//Load attributes
				}
			}
			else
				throw Exception("Bad list name " + val);
		}
	}
	catch( Exception& ex )	{
	    lout <<"WARNING: Model - Error parsing \""<<filename<<"\": "<< ex.what()<<endl;
	}
	
	calculateRanges();
}
	
void Model::draw(fVec3D gamePos, fVec3D gameRot, fVec3D eulerAngs, const fVec3D&) {
	/*
		for all Attributes
			attribute.update(gamePos, gameRot, pointOfInterest, this);
	*/
	glTranslated(gamePos.x, gamePos.y, gamePos.z);
	
	//Do the euler rotations
	glRotated(eulerAngs.x, 1, 0, 0);
	glRotated(eulerAngs.y, 0, 1, 0);
	glRotated(eulerAngs.z, 0, 0, 1);
	
	//Then our custom rotations
	glRotated(gameRot.z, 0, 0, 1);
	glRotated(gameRot.y, 0, 1, 0);
	glRotated(gameRot.x, 1, 0, 0);
	
//	lout<<"gameRot = "<<gameRot.x<<","<<gameRot.y<<","<<gameRot.z<<endl;
	
//	lout<<"Rotated by "<<gameRot.x<<","<<gameRot.y<<","<<gameRot.z<<endl;
	
	for(std::map<std::string, GeometryModel>::iterator i = models.begin(); i != models.end(); i++) {
		glPushMatrix();
			i->second.draw();
		glPopMatrix();
	}
}

void Model::calculateBoundingBox(const fVec3D& pos, double zRot, fVec2D& A, fVec2D& B, fVec2D& C, fVec2D& D) {
	zRot *= -3.1415926 / 180;
	fVec2D xRot(cos(zRot), sin(zRot));
	fVec2D yRot(-sin(zRot), cos(zRot));
	
	A = fVec2D(backBottomLeft);
	B = fVec2D(backBottomLeft.x, frontUpperRight.y);
	C = fVec2D(frontUpperRight);
	D = fVec2D(frontUpperRight.x, backBottomLeft.y);
	
	A = fVec2D(xRot | A, yRot | A);
	B = fVec2D(xRot | B, yRot | B);
	C = fVec2D(xRot | C, yRot | C);
	D = fVec2D(xRot | D, yRot | D);
	
	A += pos;
	B += pos;
	C += pos;
	D += pos;
}

void Model::calculateRanges() { 
	bool set = false;
	for(std::map<std::string, GeometryModel>::iterator i = models.begin(); i != models.end(); i++) {
		fVec3D bbl = i->second.getBackLowerLeft();
		fVec3D fur = i->second.getFrontUpperRight();
		if(!set) {
			set = true;
			backBottomLeft = bbl;
			frontUpperRight = fur;
			continue;
		}
		if(bbl.x < backBottomLeft.x)	backBottomLeft.x = bbl.x;
		if(bbl.y < backBottomLeft.y)	backBottomLeft.y = bbl.y;
		if(bbl.z < backBottomLeft.z)	backBottomLeft.z = bbl.z;
		if(fur.x > frontUpperRight.x)	frontUpperRight.x = fur.x;
		if(fur.y > frontUpperRight.y)	frontUpperRight.y = fur.y;
		if(fur.z > frontUpperRight.z)	frontUpperRight.z = fur.z;
	}
}

